package com.airspyar;

import java.util.Vector;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;

import android.os.Handler;
import android.os.Message;
import android.util.Log;


public class PlanesDataProvider extends ThreadExtended {

	public final static int DATA_UPDATE_MESSAGE=3;
	public final static int SYNCHRONIZATION_ERROR_MESSAGE=4;
	private final static int DOWNLOAD_INTERVAL=10*1000;
	
	public final static int VISIBILITY_MIN=50;
	public final static int VISIBILITY_MAX=300;
	private final static int VISIBILITY_DEFAULT=100;
	
	private int visibilityDistance=VISIBILITY_DEFAULT;
	private Object visibilityDistanceMutex=new Object();
	
	private final ObserverDataHolder observerDataHolder;
	
	private final JsonFactory jsonFactory;
	private Vector<FlightState> visiblePlanes=null;
	private final Object visiblePlanesMutex=new Object();
	
	private final Handler handler;
	private final Timer timer;
	
	public PlanesDataProvider(Handler handler, ObserverDataHolder observerDataHolder){
		jsonFactory=new JsonFactory();
		timer=new Timer(DOWNLOAD_INTERVAL);
		this.observerDataHolder=observerDataHolder;
		this.handler=handler;
	}
	
	public void setVisibilityDistance(int newVisibility){
		synchronized(visibilityDistanceMutex){
			visibilityDistance=newVisibility;
		}
	}
	
	public int getVisibilityDistance(){
		synchronized(visibilityDistanceMutex){
			return visibilityDistance;
		}
	}
	
	public void invalidate(){
		timer.reset();
	}
	
	protected void loop(){
		if(!timer.intervalElapsed()){
			try{
				sleep(100);
			}catch(InterruptedException e){
				if(AirSpyActivity.LOG_ERROR)
					Log.e("PlanesDataProvider exception", e.getMessage());
			}
			
			return;
		}
		
		if(!SynchronizedClock.isInitialized())
			SynchronizedClock.initialize();
		if(!SynchronizedClock.isInitialized())
			handler.sendEmptyMessage(SYNCHRONIZATION_ERROR_MESSAGE);
			
			
		try{
			Vector<FlightState> newVisiblePlanes=getVisiblePlanes();
			if(newVisiblePlanes==null)
				return;
			
			synchronized(visiblePlanesMutex){
				visiblePlanes=newVisiblePlanes;
			}
					
			if(isKilled() || isPaused())
				return;
				
			Message msg=new Message();
			msg.what=DATA_UPDATE_MESSAGE;
			msg.obj=newVisiblePlanes;
			handler.sendMessage(msg);
				
		}catch(Exception e){
			if(AirSpyActivity.LOG_ERROR)
				Log.e("PlanesDataProvider exception", "Could not get visible planes: "+e.getMessage());
		}
	}

	
	public Vector<FlightState> getPlanes(){
		synchronized(visiblePlanesMutex){
			return visiblePlanes;
		}
	}
	
	private Vector<FlightState> getVisiblePlanes() throws Exception{		
		SimpleLocation observerLocation=observerDataHolder.getSimpleLocation();
		if(observerLocation==null)
			return null;
		
		
		String data=Utils.fetchPage("http://www.flightradar24.com/PlaneFeed.json", 5000, 30000);
		JsonParser jp=jsonFactory.createJsonParser(data);
		
		Vector<FlightState> planes=new Vector<FlightState>();
		
		String callsign, hex, reg;
		float latitude, longtitude, altitude, dLong, dLat;
		long time;
		int speed, track;
		
		if(jp.nextToken()!=JsonToken.START_OBJECT)
			return null;
		
		while(jp.nextToken()==JsonToken.FIELD_NAME){			
			if(isKilled() || isPaused())
				break;
			
			
			try{
				callsign=jp.getText();
				jp.nextToken();
				jp.nextToken();
				
				hex=jp.getText();
				
				jp.nextToken();
				latitude=(float)jp.getValueAsDouble();
	
				jp.nextToken();
				longtitude=(float)jp.getValueAsDouble();
				
				
				dLat=Math.abs(observerLocation.getLat()-latitude);
				dLong=Math.abs(observerLocation.getLong()-longtitude);		
				if(dLong>180) dLong=360-dLong;
				
				if(dLong+dLat>8){
					rewind(jp);
					continue;
				}
				
				
				jp.nextToken();
				track=jp.getValueAsInt();
				
				jp.nextToken();
				altitude=jp.getValueAsInt();
				altitude*=0.3048;
				
	
				jp.nextToken();
				speed=jp.getValueAsInt();
				speed*=1.852;
				
				
				jp.nextToken();
				jp.nextToken();
				jp.nextToken();

				jp.nextToken();
				reg=jp.getText();
				
				jp.nextToken();
				time=jp.getValueAsLong();
				time*=1000;
				
				
			}catch(Exception e){
				if(AirSpyActivity.LOG_ERROR)
					Log.e("PlanesDataProvider exception", "Unable to parse data: "+e.getMessage());
				
				rewind(jp);
				continue;
			}

			SimpleLocation planeLocation=new SimpleLocation(latitude, longtitude, altitude/1000f);
			Vector3d distanceVector=Utils.calculateVector3d(observerLocation, planeLocation);
			float distance=distanceVector.lenght();
			if(distance<this.getVisibilityDistance())
				planes.add(new FlightState(planeLocation, callsign, reg, hex, speed, track, distanceVector, time));

			rewind(jp);
		}

		jp.close();
		return planes;
	}
	
	private static void rewind(JsonParser jp) throws Exception{
		JsonToken next;
		do{
			next=jp.nextToken();
			if(next==JsonToken.END_OBJECT)
				jp.close();
			
		}while(next!=JsonToken.END_ARRAY && !jp.isClosed());
	}
}
